﻿using System;
using System.Linq;

namespace Ukagaka.Named.Ghost.Shiori
{
	/// <summary>
	/// 解析可能な列挙型を定義します
	/// </summary>
	/// <typeparam name="T">列挙型</typeparam>
	public abstract class ParseableEnum<T> : IParseable
		where T : struct
	{
		/// <summary>
		/// 値を取得します
		/// </summary>
		public T Value
		{
			get;
			set;
		}

		/// <summary>
		/// 解析可能な列挙型を初期化します
		/// </summary>
		/// <param name="value">値</param>
		public ParseableEnum( T value )
		{
			Value = value;
		}

		/// <summary>
		/// 解析可能な列挙型を初期化します
		/// </summary>
		/// <param name="value">値</param>
		public ParseableEnum( string value )
		{
			Parse( value );
		}

		/// <summary>
		/// メソッドの種別を解析します
		/// </summary>
		/// <param name="value">メソッドの種別</param>
		public virtual void Parse( string value )
		{
			foreach ( var fieldInfo in typeof( T ).GetFields( ) )
			{
				var attrs = fieldInfo.GetCustomAttributes( typeof( NameAttribute ), false ).OfType<NameAttribute>( );

				if ( attrs.Any( x => x.Name.Equals( value, StringComparison.OrdinalIgnoreCase ) ) )
				{
					Value = ( T )fieldInfo.GetValue( null );

					return;
				}
			}

			throw new InvalidOperationException( "解析可能な型への変換ができない値が指定されています" );
		}

		/// <summary>
		/// メソッドの種別を取得します
		/// </summary>
		/// <returns>メソッドの種別</returns>
		public override string ToString( )
		{
			var type = Value.GetType( );
			var fieldInfo = type.GetField( Enum.GetName( type, Value ) );
			var attrs = fieldInfo.GetCustomAttributes( typeof( NameAttribute ), false ).OfType<NameAttribute>( );

			if ( attrs.Any( ) )
			{
				return attrs.First( ).Name;
			}
			else
			{
				return string.Format( "{0}", Value );
			}
		}
	}
}
